#ifndef _MONSTER_TEST_H
#define _MOSNTER_TEST_H_

#include "Monster.h"

#include "RegularSoldierNamable.h"
#include "RegularSoldierRepresentable.h"
#include "RegularSoldierMovable.h"
#include "RegularSoldierLiving.h"

#include "mock_INamable.h"
#include "mock_IRepresentable.h"
#include "mock_ILiving.h"
#include "mock_IMovable.h"

#include "gmock/gmock.h"
#include "gtest/gtest.h"

using ::testing::AtLeast;
using ::testing::Return;
using ::testing::ReturnRef;
/**
 * This is a simple test, just to check if appropiate function
 * for name getting is called by the Monster implementation.
 * We expect that the function getName from INamable will be called.
 */
TEST(Monster_INamableMock, nameGetting)
{
  const std::string n = "Mock Name";

  INamableMock namable_mock;

  EXPECT_CALL(namable_mock, getName())
    .Times(AtLeast(1))
    .WillOnce(ReturnRef(n));
  
  RegularSoldierRepresentable r;
  RegularSoldierMovable m;
  RegularSoldierLiving l;
  Monster monster(&namable_mock, &r, &m, &l);

  EXPECT_TRUE(n == monster.getName());
}

/**
 * This is a simple test to check if the Monster class
 * calls the appropiate method, to get the representation.
 * It sets a return value, calls the method to get the representation
 * and checks the mocked value just in case.
 */
TEST(Monster_IRepresentableMock, representationGet)
{
  IRepresentableMock representable_mock;

  EXPECT_CALL(representable_mock, getAsciiRepresentation())
    .Times(AtLeast(1))
    .WillOnce(Return('M'));

  RegularSoldierNamable n;
  RegularSoldierMovable m;
  RegularSoldierLiving l;
  Monster monster(&n, &representable_mock, &m, &l);

  EXPECT_TRUE('M' == monster.getAsciiRepresentation());
}

TEST(Monster_IMovableMock, gettingPosition)
{
  IMovable::movableVector v;
  const int X_POS = 5;
  const int Y_POS = -10; 
  v.push_back(X_POS);
  v.push_back(Y_POS);

  IMovableMock movable_mock;

  EXPECT_CALL(movable_mock, getPosition())
    .Times(AtLeast(1))
    .WillOnce(ReturnRef(v));

  RegularSoldierNamable n;
  RegularSoldierRepresentable r;
  RegularSoldierLiving l;
  Monster monster(&n, &r, &movable_mock, &l);

  EXPECT_TRUE(v == monster.getPosition());
}

/**
 * Check if Monster class is calling appropiate function
 * to set position.
 */
TEST(Monster_IMovableMock, settingPosition)
{
  IMovable::movableVector v;
  const int X_POS = -10;
  const int Y_POS = 5; 
  v.push_back(X_POS);
  v.push_back(Y_POS);

  IMovableMock movable_mock;

  EXPECT_CALL(movable_mock, setPosition(v))
    .Times(AtLeast(1));

  RegularSoldierNamable n;
  RegularSoldierRepresentable r;
  RegularSoldierLiving l;
  Monster monster(&n, &r, &movable_mock, &l);

  monster.setPosition(v);
}

/**
 * Checks if appropiate move function is called from Monster class.
 */
TEST(Monster_IMovableMock, movingPosition)
{
  IMovable::movableVector v;
  const int X_POS = -10;
  const int Y_POS = -10; 
  v.push_back(X_POS);
  v.push_back(Y_POS);

  IMovableMock movable_mock;

  EXPECT_CALL(movable_mock, movePosition(v))
    .Times(AtLeast(1));

  RegularSoldierNamable n;
  RegularSoldierRepresentable r;
  RegularSoldierLiving l;
  Monster monster(&n, &r, &movable_mock, &l);

  monster.movePosition(v);
}

/**
 * Checks if appropiate getHealth method is called
 * from Monster class.
 */
TEST(Monster_ILivingMock, gettingHealth)
{
  const int HEALTH = 10;
  ILivingMock living_mock;

  EXPECT_CALL(living_mock, getHealth())
    .Times(AtLeast(1))
    .WillOnce(Return(HEALTH));

  RegularSoldierNamable n;
  RegularSoldierRepresentable r;
  RegularSoldierMovable m;
  Monster monster(&n, &r, &m, &living_mock);

  EXPECT_TRUE(HEALTH == monster.getHealth());
}

/**
 * Test to check of appropiate hurt method is called.
 */
TEST(Monster_ILivingMock, hurting)
{
  const int DAMAGE = 10;
  ILivingMock living_mock;

  EXPECT_CALL(living_mock, hurt(DAMAGE))
    .Times(AtLeast(1));

  RegularSoldierNamable n;
  RegularSoldierRepresentable r;
  RegularSoldierMovable m;
  Monster monster(&n, &r, &m, &living_mock);

  monster.hurt(DAMAGE);
}

/**
 * Test to check if heal method is called
 * for the mocked function.
 */
TEST(Monster_ILivingMock, healing)
{
  const int HEALTH = 15;
  ILivingMock living_mock;

  EXPECT_CALL(living_mock, heal(HEALTH))
    .Times(AtLeast(1));

  RegularSoldierNamable n;
  RegularSoldierRepresentable r;
  RegularSoldierMovable m;
  Monster monster(&n, &r, &m, &living_mock);

  monster.heal(HEALTH);
}

/**
 * More of a dummy test to satisfy the coverage. We call setKillCallBack
 * explicitly.
 */
TEST(Monster_ILivingMock, setKillCallBack)
{
  ILivingMock living_mock;

  EXPECT_CALL(living_mock, setKillCallback(0))
    .Times(AtLeast(1));

  living_mock.setKillCallback(0);

  RegularSoldierNamable n;
  RegularSoldierRepresentable r;
  RegularSoldierMovable m;
  Monster monster(&n, &r, &m, &living_mock);
}

#endif /* _MONSTER_TEST_H_ */

